package ua.openmedis.dao.impl;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.InvalidTokenOffsetsException;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.apache.lucene.util.Version;
import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.Search;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ua.openmedis.ServerUtils;
import ua.openmedis.dao.api.AssetGenericNameDAO;
import ua.openmedis.domain.AssetGenericName;

public class AssetGenericNameDAOImpl implements AssetGenericNameDAO {
	private final static Logger log = LoggerFactory.getLogger(AssetGenericNameDAOImpl.class);
	
	// TODO inject
	EntityManager em = ServerUtils.getEntityManager();;

	@Override
	public List<AssetGenericName> findAll() {
		if (em != null) {
			log.debug("EntityManager is not null");
			List<AssetGenericName> names = em.createQuery("select a from AssetGenericName a",
					AssetGenericName.class).getResultList();
			for (AssetGenericName assetGenericName : names){
				assetGenericName.setGenericAssetNameHighlighted(assetGenericName.getGenericAssetName());
			}
			return names;
		} else {
			log.debug("EntityManaher is NULL!!!");
			return new ArrayList<AssetGenericName>(0);
		}
	}

	@SuppressWarnings({ "unchecked" })
	@Override
	public List<AssetGenericName> findByName(String genericAssetName) {
		FullTextEntityManager fteManager = Search.getFullTextEntityManager(em);
		Analyzer analyzer = fteManager.getSearchFactory().getAnalyzer("customanalyzer");
		QueryParser parser = new QueryParser(Version.LUCENE_31, 
				"genericAssetName", analyzer);
		Query lucenceQuery = null;
		try {
			lucenceQuery = parser.parse(genericAssetName);
			log.debug("Lucene Query: " + lucenceQuery);
		} catch (ParseException e) {
			throw new RuntimeException("Cannot search with query string",e);
		}
		
		List<AssetGenericName> names = fteManager.createFullTextQuery(lucenceQuery,
				AssetGenericName.class).getResultList();
	
		SimpleHTMLFormatter formatter = new SimpleHTMLFormatter("[", "]");
		QueryScorer scorer = new QueryScorer(lucenceQuery);
		Highlighter highlighter = new Highlighter(formatter, scorer);
		
		int maxNumFragmentsRequired = 10;
		for (AssetGenericName assetGenericName : names){
			String text = assetGenericName.getGenericAssetName();
			TokenStream tokenStream = analyzer.tokenStream(genericAssetName, new StringReader(text));
			try {
				String result = highlighter.getBestFragments(tokenStream, 
						text, maxNumFragmentsRequired, "");
				assetGenericName.setGenericAssetNameHighlighted(result);
			} catch (IOException e) {
				throw new RuntimeException(e);
			} catch (InvalidTokenOffsetsException itoe) {
				throw new RuntimeException(itoe);
			}
		}
		
		return names;
	}

	public void indexDatabase(){
		FullTextEntityManager fteManager = Search.getFullTextEntityManager(em);
		try {
			fteManager.createIndexer().startAndWait();
		} catch (InterruptedException e) {
			throw new RuntimeException("Cannot index database",e);
		}
 	}
}
